package models

import (
	"fmt"
	"strconv"

	"github.com/astaxie/beego/logs"
	"github.com/astaxie/beego/orm"
	"strings"
)

type AiProcess struct {
	Id               int64
	Name             string //流程名称
	Node             int    //任务节点
	Node_name        string //节点名称
	Node_type        int    //节点类型，0为语音文件，1为TTS文字
	Node_content     string //节点内容，根据类型，文字或者录音文件绝对地址
	Keyword          string //关键字，以 “|”分隔
	Owner_tpl_id     int64  //归属模板id
	Scene            int    //场景；语境；情景；0为肯定，1为否定，2为强烈拒绝，3为未知
	Ai_order         int    //节点优先关系处理
	Mode             int    //打断。0支持打断，1支持不打断，2支持按需求打断
	Target           int64  //该节点的下一节点id
	Node_desc        string //描述该节点最终叙述的详细内容
	Action           int64  //动作 0:下一级,1：跳转，2：再说一遍，3：挂断，4，转人工
	Min_speak_ms     int    `orm:"default(100)"`   //最小通话时间
	Min_pause_ms     int    `orm:"default(500)"`   //最小间隔时间
	Max_waiting_ms   int    `orm:"default(5000)"`  //最大等待时间
	Max_recording_ms int    `orm:"default(10000)"` //最大录音时间
	Gain             int    //增益
	Retry            int    //重置
	Parent_id        int64  //父级节点
	B_interrupt      bool   //父级节点
	Tpl_target       int64  //目标模板
	Adjust_keyword   string //校正词
}

type AiProcessContent struct {
	Id         int64
	Process_id int64  //process 的内容
	Type       int    //节点类型，0为语音文件，1为TTS文字
	Content    string //节点内容，根据类型，文字或者录音文件绝对地址
	Ai_order   int    //序列
	Audio_path string //文件路径
}
type AiProcessNode struct {
	Id        int64
	Parent_id int64 //process 的内容
}

func (a *AiProcess) TableName() string {
	return TableName("process")
}

func (a *AiProcessContent) TableName() string {
	return TableName("process_content")
}

func ProcessAdd(p *AiProcess) (int64, error) {
	return orm.NewOrm().Insert(p)
}

func ProcessContentAdd(p *AiProcessContent) (int64, error) {
	return orm.NewOrm().Insert(p)
}

//获取列表
func ProcessGetList(page, pageSize int, tableName string, filters ...interface{}) ([]*AiProcess, int64) {
	offset := (page - 1) * pageSize
	list := make([]*AiProcess, 0)
	query := orm.NewOrm().QueryTable(TableName(tableName))
	//过滤 条件。
	if len(filters) > 0 {
		fmt.Println(filters[0].(string), filters[1])
		for i := 0; i < len(filters); i += 2 {
			query = query.Filter(filters[i].(string), filters[i+1])
		}
	}
	total, _ := query.Count()
	_, err := query.OrderBy("-id").Limit(pageSize, offset).All(&list)
	//_, err := query.OrderBy("node", "ai_order").Limit(pageSize, offset).All(&list)//按照节点之后按照优先级排序
	if err != nil {
		ErrorLog(err)
	}
	return list, total
}

//获取节点内容列表
func ProcessContentGetList(page, pageSize int, tableName string, filters ...interface{}) ([]*AiProcessContent, int64) {
	offset := (page - 1) * pageSize
	list := make([]*AiProcessContent, 0)
	query := orm.NewOrm().QueryTable(TableName(tableName))
	//过滤 条件。
	if len(filters) > 0 {
		fmt.Println(filters[0].(string), filters[1])
		for i := 0; i < len(filters); i += 2 {
			query = query.Filter(filters[i].(string), filters[i+1])
		}
	}
	total, _ := query.Count()
	var err error
	if page == -1 {
		_, err = query.OrderBy("id").All(&list)
	} else {
		_, err = query.OrderBy("id").Limit(pageSize, offset).All(&list)
	}
	if err != nil {
		ErrorLog(err)
	}
	return list, total
}

//根据ID查询 获取process
func ProcessGetById(id int) (*AiProcess, error) {
	r := new(AiProcess)
	err := orm.NewOrm().QueryTable(TableName("process")).Filter("id", id).One(r)
	if err != nil {
		ErrorLog(err)
		return nil, err
	}
	return r, nil
}

//根据tplID查询 获取process
func ProcessGetByTplId(id int64, node int, parent_id int64) (*AiProcess, error) {
	r := new(AiProcess)
	err := orm.NewOrm().QueryTable(TableName("process")).Filter("owner_tpl_id", id).Filter("node", node).Filter("parent_id", parent_id).One(r)
	if err != nil {
		ErrorLog(err)
		return nil, err
	}
	return r, nil
}

//根据tplID查询 获取process
func ProcessNoIdGetByTplId(id int64, node int) (int64, *AiProcess, error) {
	r := new(AiProcess)
	err := orm.NewOrm().QueryTable(TableName("process")).Filter("owner_tpl_id", id).Filter("node", node).One(r)
	if err != nil {
		ErrorLog(err)
		return 0, nil, err
	}

	r1 := new(AiProcess)
	sqlstr := "SELECT  T0.name, T0.node, T0.node_name, T0.node_type, T0.node_content, " +
		"T0.keyword, T0.owner_tpl_id, T0.scene, T0.ai_order, T0.mode, T0.target, T0.node_desc, " +
		"T0.action, T0.min_speak_ms, T0.min_pause_ms, T0.max_waiting_ms, T0.max_recording_ms, T0.gain, " +
		"T0.retry, T0.parent_id, T0.b_interrupt " +
		"FROM ai_process T0 WHERE T0.owner_tpl_id = " + strconv.FormatInt(id, 10) + " AND T0.node = " + strconv.Itoa(node) + "  LIMIT 1"
	err = orm.NewOrm().Raw(sqlstr).QueryRow(&r1)
	if err != nil {
		ErrorLog(err)
		return 0, nil, err
	}
	return r.Id, r1, nil
}

//根据tplID查询 获取process
func ProcessContentByProcess(id int64) (*AiProcessContent, error) {
	r := new(AiProcessContent)
	sqlstr := "select	Process_id ,Type ,Content ,Ai_order ,Audio_path " +
		"FROM ai_process_content WHERE process_id = " + strconv.FormatInt(id, 10) + "  LIMIT 1"
	err := orm.NewOrm().Raw(sqlstr).QueryRow(&r)
	if err != nil {
		ErrorLog(err)
		return nil, err
	}
	return r, nil
}

//根据ID查询 获取process
func ProcessContentGetById(id int) (*AiProcessContent, error) {
	r := new(AiProcessContent)
	err := orm.NewOrm().QueryTable(TableName("process_content")).Filter("id", id).One(r)
	if err != nil {
		ErrorLog(err)
		return nil, err
	}
	return r, nil
}

//根据节点ID查询 所有数组
func ProcessGetNodeArr(id int64, node string) ([]*AiProcess, error) {
	arr := make([]*AiProcess, 0)
	//_ , err :=
	_, err := orm.NewOrm().QueryTable(TableName("process")).Filter("owner_tpl_id", id).GroupBy(node, "id").OrderBy(node).All(&arr)

	if err != nil {
		ErrorLog(err)
		return nil, err
	}
	return arr, nil
}

//根据节点ID查询 所有全局数组
func ProcessGetGlobalNodeArr(id int64, node int) ([]*AiProcess, error) {
	arr := make([]*AiProcess, 0)
	//_ , err :=
	_, err := orm.NewOrm().QueryTable(TableName("process")).Filter("owner_tpl_id", id).Filter("node", node).All(&arr)

	if err != nil {
		ErrorLog(err)
		return nil, err
	}
	return arr, nil
}

func ProcessGetChildArr(tpl int, node int, parent int64) ([]AiProcessNode, error) {
	parentId := []AiProcessNode{}

	SqlStr := "SELECT id,parent_id FROM ai_process WHERE owner_tpl_id=" + strconv.Itoa(tpl) + " and node=" + strconv.Itoa(node) + " and parent_id=" + strconv.FormatInt(parent, 10)

	_, err := orm.NewOrm().Raw(SqlStr).QueryRows(&parentId)
	if err != nil {
		logs.Error("获取子节点 ai_process 163 err", err)
		return parentId, err
	}
	return parentId, err
}

//根据id 修改关键字
func UpdateKeywordFromId(keyword string, id int64) error {

	sql := "UPDATE ai_process set keyword='" + keyword + "' WHERE id=" + strconv.FormatInt(id, 10)
	_, err := orm.NewOrm().Raw(sql).Exec()
	if err != nil {
		ErrorLog(err)
		return err
	}
	return nil

}

//根据processid 修改node_content
func UpdateNodeContentFromId(nodeContent string, id int64) error {

	sql := "UPDATE ai_process set node_content='" + nodeContent + "' WHERE id=" + strconv.FormatInt(id, 10)
	_, err := orm.NewOrm().Raw(sql).Exec()
	if err != nil {
		ErrorLog(err)
		return err
	}
	return nil

}

//更新数据库
func (a *AiProcess) Update(fields ...string) error {
	if _, err := orm.NewOrm().Update(a, fields...); err != nil {
		ErrorLog(err)
		return err
	}
	return nil
}

//更新数据库
func (a *AiProcessContent) Update(fields ...string) error {
	if _, err := orm.NewOrm().Update(a, fields...); err != nil {
		ErrorLog(err)
		return err
	}
	return nil
}

//删除数据库
func (a *AiProcess) Delete(fields ...string) error {
	SqlStr := "with recursive u as " +
		"(select id from ai_process where parent_id=" + strconv.FormatInt(a.Id, 10) + "or id=" + strconv.FormatInt(a.Id, 10) + " union  select b.id from ai_process b,u where b.parent_id=u.id) " +
		"delete from  ai_process where id in (select id from u)"
	_, err := orm.NewOrm().Raw(SqlStr).Exec()
	if err != nil {
		ErrorLog(err)
		return err
	}
	return nil
}

//删除数据库
func (a *AiProcessContent) Delete(fields ...string) error {
	if _, err := orm.NewOrm().Delete(a, fields...); err != nil {
		ErrorLog(err)
		return err
	}
	return nil
}

//获取节点内容列表
func GetProcessMessage(keyword string, tpl_id int64) (*AiProcess, error) {

	list := new(AiProcess)
	SqlStr := "SELECT *" +
		" FROM ai_process WHERE owner_tpl_id=" + strconv.FormatInt(tpl_id, 10) + " and keyword ~ '" + keyword +
		"' order by ai_order limit 1;"
	err1 := orm.NewOrm().Raw(SqlStr).QueryRow(&list)
	if err1 != nil {
		ErrorLog(err1)
	}
	list, err := ProcessGetById(int(list.Target))
	if err != nil {
		ErrorLog(err)
		return nil, err
	}

	return list, nil

}
func processByProcessIdUpdateTarget(target, id string) error {

	SqlStr := "UPDATE ai_process " +
		"SET target=" + target + " WHERE id = " + id
	fmt.Println(SqlStr)
	_, err := orm.NewOrm().Raw(SqlStr).Exec()
	if err != nil {
		ErrorLog(err)
		return err
	}
	return nil
}

//拷贝模板
func CopyTpl(tpl, id int64) error {

	var process AiProcess
	err := orm.NewOrm().QueryTable(TableName("process")).Filter("owner_tpl_id", tpl).Filter("node", 0).One(&process)
	if err != nil {
		ErrorLog(err)
		return err
	}
	global(-5, tpl, 0, id, 0)
	global(-6, tpl, 0, id, 0)
	arr := copyprocess(0, tpl, 0, id, 0, []string{})
	//查询所有  全局节点
	var processlist []AiProcess
	_, err = orm.NewOrm().QueryTable(TableName("process")).Filter("owner_tpl_id", id).All(&processlist)
	if err != nil {
		ErrorLog(err)
		return err
	}
	for _, v := range processlist {

		if v.Action == 1 {
			for _, v1 := range arr {
				strs := strings.Split(v1, ",") //切分所有v的^
				if strs[0] == strconv.FormatInt(v.Target, 10) {
					processByProcessIdUpdateTarget(strs[1], strconv.FormatInt(v.Id, 10))
					continue
				}
			}
		}
	}

	//查询所有  全局节点
	var list []AiProcess
	_, err = orm.NewOrm().QueryTable(TableName("process")).Filter("owner_tpl_id", tpl).Filter("node", -1).All(&list)
	if err != nil {
		ErrorLog(err)
		return err
	}
	for _, v := range list {
		var newId = addprocess(v, id, 0)
		if v.Action == 1 {
			for _, v1 := range arr {
				strs := strings.Split(v1, ",") //切分所有v的^
				if strs[0] == strconv.FormatInt(v.Target, 10) {
					processByProcessIdUpdateTarget(strs[1], strconv.FormatInt(newId, 10))
					continue
				}
			}
		}
		var nNode, isUpdate = checkoutNodeContent(v.Node_content, newId) //检查node是否有录音
		if isUpdate {
			UpdateNodeContentFromId(nNode, newId)
		}
	}
	return nil
}

//node:节点,tpl:旧的tplid, parent:查询子节点用的父节点, tpl_id：新的tplid,id:新生成的父节点id
func copyprocess(node int, tpl, parent, tpl_id, pid int64, arr []string) []string {
	var list []AiProcess
	_, err := orm.NewOrm().QueryTable(TableName("process")).Filter("owner_tpl_id", tpl).Filter("parent_id", parent).Filter("node", node).All(&list)
	if err != nil {
		fmt.Printf("error:", err)
		return []string{}
	}
	//arr:= []string{"1","2"}
	for _, v := range list {
		var newid = addprocess(v, tpl_id, pid)                           //添加节点
		var nNode, isUpdate = checkoutNodeContent(v.Node_content, newid) //检查node是否有录音
		if isUpdate {
			UpdateNodeContentFromId(nNode, newid)
		}
		global(-2, tpl, v.Id, tpl_id, newid)
		global(-3, tpl, v.Id, tpl_id, newid)
		arr = append(arr, strconv.FormatInt(v.Id, 10)+","+strconv.FormatInt(newid, 10))
		arr = copyprocess(node+1, tpl, v.Id, tpl_id, newid, arr) //递归循环
	}
	return arr
}

//查看是否有录音文件
func checkoutNodeContent(str string, nid int64) (string, bool) {
	var arr = strings.Split(str, "^") //取出node_content是否多段录音
	var nstr = ""
	var noUpdate = false
	for k, v := range arr {
		var record = strings.Split(v, "`") //取出node_content是否有录音
		nstr += record[0]                  //先把内容加进去
		if len(record) > 1 {               //如果大于1，那么就有process_content
			noUpdate = true //如果有更新process , 那么就至于true ，需要去替换process中的node_content
			var process_content AiProcessContent
			orm.NewOrm().QueryTable(TableName("process_content")).Filter("id", record[1]).One(&process_content)
			addProcesscontent(process_content, nid) //添加新的 processContent
			nstr += "`" + strconv.FormatInt(process_content.Id, 10)
		}
		if len(arr)-1 > k {
			nstr += "^"
		}
	}
	return nstr, noUpdate

}

//拷贝全局
func global(node int, tpl, parent, tpl_id, pid int64) {
	var process AiProcess
	err := orm.NewOrm().QueryTable(TableName("process")).Filter("owner_tpl_id", tpl).Filter("parent_id", parent).Filter("node", node).One(&process)
	fmt.Println(process, "===", tpl_id, pid)
	if err != nil {
		fmt.Printf("error:", err)
		return
	}
	var newid = addprocess(process, tpl_id, pid)
	// 根据 process.id  查找到对应的 process_content 的内容，然后根据 pid 当process_content的pid ,新增新的process_content
	var process_content AiProcessContent
	err = orm.NewOrm().QueryTable(TableName("process_content")).Filter("process_id", process.Id).One(&process_content)
	addProcesscontent(process_content, newid) //添加新的 processContent
}

//添加流程
func addprocess(v AiProcess, tpl_id, pid int64) int64 {
	var Process AiProcess
	Process.Name = v.Name                 //流程名称
	Process.Node = v.Node                 //任务节点
	Process.Node_name = v.Node_name       //节点名称
	Process.Node_type = v.Node_type       //节点类型，0为语音文件，1为TTS文字
	Process.Node_content = v.Node_content //节点内容，根据类型，文字或者录音文件绝对地址
	Process.Keyword = v.Keyword           //关键字

	Process.Owner_tpl_id = tpl_id //归属模板id
	Process.Scene = v.Scene       //场景；语境；情景；0为肯定，1为否定，2为强烈拒绝，3为未知
	Process.Ai_order = v.Ai_order //节点优先关系处理
	Process.Mode = v.Mode
	Process.Target = v.Target

	Process.Node_desc = v.Node_desc //节点描述
	Process.Action = v.Action
	Process.Min_speak_ms = v.Min_speak_ms
	Process.Min_pause_ms = v.Min_pause_ms
	Process.Max_waiting_ms = v.Max_waiting_ms
	Process.Max_recording_ms = v.Max_recording_ms
	Process.Gain = v.Gain
	Process.Retry = v.Retry
	Process.Parent_id = pid
	Process.B_interrupt = v.B_interrupt
	var newid, _ = ProcessAdd(&Process)
	return newid
}

func addProcesscontent(process_content AiProcessContent, newid int64) {
	var pc AiProcessContent
	pc.Ai_order = process_content.Ai_order
	pc.Audio_path = process_content.Audio_path
	pc.Content = process_content.Content
	pc.Process_id = newid
	pc.Type = process_content.Type
	ProcessContentAdd(&pc)
}

//获取内容
func GetNodeProcessMessage(node int, tpl_id int64) (*AiProcess, error) {

	list := new(AiProcess)
	SqlStr := "SELECT node_content,id,Name,Node,Node_name,Node_type," +
		"Keyword,Owner_tpl_id,Scene,ai_order,mode,Target,Node_desc,Action" +
		" FROM ai_process WHERE owner_tpl_id=" + strconv.FormatInt(tpl_id, 10) + " and node='" + strconv.Itoa(node) +
		"' order by ai_order limit 1;"
	err := orm.NewOrm().Raw(SqlStr).QueryRow(&list)
	if err != nil {
		ErrorLog(err)
		return nil, err
	}

	return list, nil

}

type AiProcessNodeAndTpl struct {
	Node         int
	Owner_tpl_id int64 //process 的内容
}

//获取内容
func SetNodePositionMode(id, parent int64) error {
	parentStr := strconv.FormatInt(parent, 10)                                        //获取跳转的id
	idstr := strconv.FormatInt(id, 10)                                                //获取当前
	parentNodeStr := "SELECT node,owner_tpl_id FROM ai_process WHERE id=" + parentStr //获取跳转的节点
	idNodeStr := "SELECT node FROM ai_process WHERE id=" + idstr                      //获取当前的节点
	var idNode int
	var nodeAndTpl AiProcessNodeAndTpl
	err := orm.NewOrm().Raw(parentNodeStr).QueryRow(&nodeAndTpl)
	err = orm.NewOrm().Raw(idNodeStr).QueryRow(&idNode)

	SqlStr := "UPDATE ai_process SET parent_id=" + parentStr + ",node=" + strconv.Itoa(nodeAndTpl.Node+1) + " WHERE id=" + idstr
	_, err = orm.NewOrm().Raw(SqlStr).Exec()
	if err != nil {
		ErrorLog(err)
		return err
	}
	caNode := idNode - (nodeAndTpl.Node + 1) //当前id减跳转的id
	updataChlidNode(caNode, idNode+1, nodeAndTpl.Owner_tpl_id, id)

	return nil

}

//node:节点,tpl:旧的tplid, parent:查询子节点用的父节点, tpl_id：新的tplid,id:新生成的父节点id
func updataChlidNode(ca, node int, tpl, parent int64) {
	var list []AiProcess
	_, err := orm.NewOrm().QueryTable(TableName("process")).Filter("owner_tpl_id", tpl).Filter("parent_id", parent).Filter("node", node).All(&list)
	if err != nil {
		fmt.Printf("error:", err)
		ErrorLog(err)
		return
	}
	for _, v := range list {
		updataChlidNode(ca, v.Node+1, tpl, v.Id) //递归循环
		SqlStr := "UPDATE ai_process SET node=" + strconv.Itoa(v.Node-ca) + " WHERE id=" + strconv.FormatInt(v.Id, 10)
		_, err = orm.NewOrm().Raw(SqlStr).Exec()
		if err != nil {
			ErrorLog(err)
			return
		}
	}
	return
}

//复制porcees
func CopyNodeProcess(id int64) {
	process,_:=ProcessGetById(int(id))
	process.Node=process.Node+1
	pid:=addprocess(*process,process.Owner_tpl_id,id)//复制节点
	global(-2, process.Owner_tpl_id, process.Id, process.Owner_tpl_id, pid)//新增静音
	global(-3, process.Owner_tpl_id, process.Id, process.Owner_tpl_id, pid)//新增不匹配
}

/**
根据节点获取当前节点的关键字
node: 当前节点
tpl_id: 模板id
return :process对象
*/
func ProcessToNodeForKeyword(node int, tpl_id int64) ([]*AiProcess, error) {

	list := []*AiProcess{}
	SqlStr := "SELECT * FROM ai_process WHERE owner_tpl_id=" + strconv.FormatInt(tpl_id, 10) +
		" and node=" + strconv.Itoa(node) + " order by ai_order"
	_, err := orm.NewOrm().Raw(SqlStr).QueryRows(&list)

	if err != nil {
		ErrorLog(err)
		return nil, err
	}

	return list, nil
}

func (a *AiProcessContent) ProcessContentByProcessId() error {

	SqlStr := "UPDATE ai_process_content " +
		"SET content='" + a.Content + "',type=" + strconv.Itoa(a.Type) + ",ai_order=" + strconv.Itoa(a.Ai_order) +
		",audio_path='" + a.Audio_path + "' WHERE process_id = " + strconv.FormatInt(a.Process_id, 10)
	_, err := orm.NewOrm().Raw(SqlStr).Exec()
	if err != nil {
		ErrorLog(err)
		return err
	}
	return nil
}

type TplGlobal struct {
	Tpl_id       int64
	Process_id   int64
	Node         int
	Node_type    int
	Node_content string
	Audio_path   string
}

func GetTplMuteAndMisMatchingById(tpl_id int64) ([]*TplGlobal, error) {
	tpl_global := make([]*TplGlobal, 0)
	SqlStr := "select t.id tplid, c.process_id process_id, p.node node, c.type node_type, c.content node_content,c.audio_path audio_path " +
		" from ai_tpl t,ai_process p ,ai_process_content c " +
		" where p.owner_tpl_id = t.id and c.process_id = p.id  and t.id = " + strconv.FormatInt(tpl_id, 10) + " and node<-1"
	_, err := orm.NewOrm().Raw(SqlStr).QueryRows(&tpl_global)
	if err != nil {
		logs.Error("get tpl global -2 -3 err", err)
	}
	return tpl_global, err
}
